package cn.ilikes.tools.nosql.jpa.unitls;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import cn.ilikes.tools.nosql.jpa.graphs.Node;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.EntityFields;

public class PropertyAccessorHelper {

	public static Object getObject(Object from, Field field) {
		if (!field.isAccessible()) {
			field.setAccessible(true);
		}

		try {
			if (from == null || field == null) {
				throw new PropertyAccessException(" form  is " + from + " or  field : " + field + " not get field value from from Object");
			}
			return field.get(from);
		} catch (IllegalArgumentException iarg) {
			throw new PropertyAccessException(iarg);
		} catch (IllegalAccessException iacc) {
			throw new PropertyAccessException(iacc);
		}
	}

	public static Object getId(Node node) {

		EntityFields entityFields = node.getEntityMetaData().getEntityId();
		Field field = entityFields.getField();
		Object id = getObject(node.getEntity(), field);
		return id;
	}

	public static Object getId(Object entity, EntityMetaData metadata) {

		EntityFields entityFields = metadata.getEntityId();
		Field field = entityFields.getField();
		Object id = getObject(entity, field);
		return id;
	}

	public static Object fieldValue(Object entity, Field field) {

		return getObject(entity, field);
	}

	public static Class<?> getGenericClass(Field field) {
		Class<?> genericClass = null;
		if (field == null) {
			return genericClass;
		}
		if (isCollection(field.getType())) {

			Type[] parameters = getTypeArguments(field);
			if (parameters != null) {
				if (parameters.length == 1) {
					genericClass = (Class<?>) parameters[0];
				} else {
					throw new PropertyAccessException("Can't determine generic class from a field that has two parameters.");
				}
			}
		}
		return genericClass != null ? genericClass : field.getType();
	}

	public static final boolean isCollection(Class<?> clazz) {
		return Collection.class.isAssignableFrom(clazz);

	}

	public static final boolean isSet(Class<?> clazz) {
		return Set.class.isAssignableFrom(clazz);

	}

	public static final boolean isList(Class<?> clazz) {
		return List.class.isAssignableFrom(clazz);

	}

	public static final Field findField(Class<?> clazz, String fieldName) {
		try {
			return clazz.getDeclaredField(fieldName);
		} catch (SecurityException e) {
			e.printStackTrace();
			return null;
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
			return null;
		}

	}

	public static boolean isRelation(EntityFields entityFields) {
		return (entityFields.getjPAField() != null && entityFields.getjPAField().isRelation());
	}

	public static Object instance(Class<?> clazz) throws PropertyAccessException {
		try {
			Object entity = clazz.newInstance();
			return entity;
		} catch (InstantiationException e) {
			throw new PropertyAccessException(e);
		} catch (IllegalAccessException e) {
			throw new PropertyAccessException(e);
		}
	}

	public static void setFieldValue(Field field, Object entity, Object value) throws PropertyAccessException {
		if (!field.isAccessible())
			field.setAccessible(true);
		try {
			field.set(entity, value);
		} catch (IllegalArgumentException e) {
			throw new PropertyAccessException(e);
		} catch (IllegalAccessException e) {
			throw new PropertyAccessException(e);
		}
	}

	/**
	 * 获得field 的泛形的类型
	 * 
	 * @return
	 */
	public static Type[] getTypeArguments(Field field) {
		Type fc = field.getGenericType(); // 关键的地方，如果是List类型，得到其Generic的类型
		if (fc == null)
			return null;
		if (fc instanceof ParameterizedType) // 【3】如果是泛型参数的类型 
		{
			ParameterizedType pt = (ParameterizedType) fc;
			return pt.getActualTypeArguments();
		}
		return null;

	}

}
